package ofertas;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import productosYPresentaciones.Producto;

/**
 * Clase abstracta que representa una oferta.
 * 
 * Se implementa el patron Composite. Esta clase es la clase Component.
 * @author Stefania/Octavio.
 */

public abstract class Oferta {

	private float porcentajeDescuento;
	
	/**
	 * Crea una oferta abstracta con un porcentaje de descuento.
	 * @param porcentaje
	 * El descuento de la Oferta.
	 */
	public Oferta(float porcentaje){
		this.setPorcentajeDescuento(porcentaje);
	}
	
	/**
	 * Obtiene el porcentaje real de la oferta.
	 * @return
	 * El porcentaje real del descuento.
	 */
	public float getPorcentajeDescuento() {
		return porcentajeDescuento;
	}

	/**
	 * Setea el porcentaje de descuento.
	 * @param porcentajeDescuento
	 * Es el porcentaje que se aplicara en la oferta.
	 */
	public void setPorcentajeDescuento(float porcentajeDescuento) {
		this.porcentajeDescuento = 1f - porcentajeDescuento;
	}
	
	/**
	 * Suma los precios del contenido de la oferta.
	 * @return
	 * El precio total sin porcentaje.
	 */
	protected abstract float calcularPrecio();
	
	/**
	 * Denota el precio real de la oferta.
	 * @return
	 * El precio con el descuento aplicado.
	 */
	public float precioOferta(){
		return this.calcularPrecio() * this.getPorcentajeDescuento();
	}
	
	/**
	 * Denota todos los productos involucrados en la oferta.
	 * @return
	 * Una lista de productos
	 */
	public abstract List<Producto> getListaProductos();
	
	public Map<Producto,Integer> getProductos(){
		Map<Producto,Integer> mapa = new HashMap<Producto,Integer>();
		for(Producto producto:this.getListaProductos()){
			this.incrementarProductoOcurrencias(mapa,producto);
			
		}
		
		return mapa;
	}
	
	private void incrementarProductoOcurrencias(Map<Producto, Integer> mapa,
			Producto producto) {
		int ocurrencias = 1;
		
		if( mapa.containsKey(producto) )
			ocurrencias += mapa.get(producto).intValue();
			
		mapa.put( producto, ocurrencias);
	}

	/**
	 * Determina si es posible aplicar una oferta a un conjunto de productos.
	 * @param productos
	 * Los productos involucrados en la consulta.
	 * @return
	 * True si puede aplicarse, False en otro caso.
	 */
	public boolean puedeAplicarOferta(Map<Producto,Integer> productosEntrantes) {
		boolean puedeAplicar = true;
		Map<Producto,Integer> productosOferta = this.getProductos();
		List<Producto> listaProductos = new ArrayList<Producto>
				( productosOferta.keySet() );
		
		for(Producto p:listaProductos){
			puedeAplicar &= puedeCubrir( p, productosOferta, productosEntrantes);
		}
		
		return puedeAplicar;
	}

	private boolean puedeCubrir(Producto p,
			Map<Producto, Integer> productosOferta,
			Map<Producto, Integer> productosEntrantes) {
		if( productosEntrantes.containsKey(p) )
			return productosOferta.get(p) <= productosEntrantes.get(p);
		return false;
	}
}
